#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
import unittest
import pprint

from metaEnhance import *

class PrintDictOnArray(dict):
    
    def __init__(self, array):
        self.array = array
    '''
    Dictionary that prints everything it sets
    '''
    def __setitem__(self, key, value):
        super(PrintDictOnArray, self).__setitem__(key, value)
        self.array.append("%s = %r" % (key, value))

class MetaEnhanceTest(unittest.TestCase):
    def output(self, out):
        self.res.append(out)
        
    def outputclass(self, cls, out):
        self.res.append(out)
        
    def createDict(self, cls):
        return PrintDictOnArray(self.res)

    def setUp(self):
        self.res = []
        meta = MetaEnhance(globals())
        meta.outFunction = "self.testprint"
        FunctionVisitor.dictionary = types.MethodType(self.createDict, FunctionVisitor)
        FunctionVisitor.output = types.MethodType(self.outputclass, FunctionVisitor)
        self.meta = meta
        self.d = Dummy()
        self.d.testprint = lambda str : self.res.append(str)
        
    def result_is(self, *args):
        self.assertEquals(list(args), self.res)
        
    def result_is_empty(self):
        self.assertEquals(0, len(self.res))
        
    def enableTrace(self):
        self.meta.trace = True


    ####################
    ## Tests
    ####################
    def testPrints(self):
        self.meta.enhanceObjectToPrintIt(self.d, self.d.add)
        self.d.add(5, 3)
        self.result_is("add 1:    return x + y")

    def testPrintsComplex(self):
        self.meta.enhanceObjectToPrintIt(self.d, self.d.complexWithIf)
        self.d.complexWithIf()
        self.result_is('complexWithIf 1:    a = 10',
                          'complexWithIf 2:    while a <= 10:',
                          'complexWithIf 3:        a += 1',
                          'complexWithIf 4:        "a is now ", a',
                          "complexWithIf 5:        'but a was then', a",
                          'complexWithIf 6:        if a > 100:',
                          'complexWithIf 8:    return True')
        
    def testTraceAssignments(self):
        self.meta.enhanceObjectToTraceAssignements(self.d, self.d.assignment)
        self.d.assignment(0)
        self.result_is('>>>> calling assignment', 'arg = 0', 'x = 10', 'y = 200',
                          'x = 100', 'x = 110', 'return value of assignment = 310\n')
        
    def testTraceSimpleAssignment(self):
        self.meta.enhanceObjectToTraceAssignements(self.d, self.d.simpleAssignment)
        self.d.simpleAssignment()
        self.result_is('>>>> calling simpleAssignment', 'x = 1',
                       'return value of simpleAssignment = 1\n')
    
    def testEnhanceObject(self):
        self.meta.enhanceObject(self.d, self.d.add)
        self.d.add(5, 3)
        self.result_is('>>>> calling add', 'x = 5', 'y = 3',
                          "add 1:    return x + y", "return value of add = 8\n")
        
    def testRemoveComments(self):
        self.meta.enhanceObjectToPrintIt(self.d, self.d.withcomment)
        self.d.withcomment()
        self.result_is("withcomment 1:    return 1")
        
    def testRemoveCommentsOnAMethodWithoutBody(self):
        self.meta.enhanceObjectToPrintIt(self.d, self.d.commentonly)
        self.d.commentonly()
        self.assertEqual([], self.res)
        
    def testIfAndElseStatemnts(self):
        self.meta.enhanceObjectToPrintIt(self.d, self.d.booleanToString)
        self.d.booleanToString(False)
        self.result_is('booleanToString 1:    if x is None:',
                          'booleanToString 5:    else:',
                          'booleanToString 6:        return "false"')
        
    def testNotAllNamesOnTheAstAreConvertedToUseADictionary(self):
        self.meta.enhanceObjectToTraceAssignements(self.d, self.d.selfnew)
        self.d.selfnew()
        self.result_is('>>>> calling selfnew', "ret = dummy object",
                       "return value of selfnew = dummy object\n")
        
        
    def testRestrictedTracing(self):
        self.meta.traceit(self.d, ['selfnew'])
        self.d.withcomment()
        self.result_is_empty()
        
        

class Dummy(object):
    def __repr__(self):
        return "dummy object"
    
    def selfnew(self):
        ret = Dummy()
        return ret
    
    def booleanToString(self, x):
        if x is None:
            return "None"
        elif x:
            return "true"
        else:
            return "false"

    
    def withcomment(self):
        '''
        with a comment
        '''
        return 1
    
    def commentonly(self):
        """with a comment"""
    
    def add(self, x, y):
        return x + y
    
    def complexWithIf(self):
        a = 10
        while a <= 10:
            a += 1
            "a is now ", a
            'but a was then', a
            if a > 100:
                return False
        return True
    
    def simpleAssignment(self):
        x = 1
        return x
    
    def assignment(self, arg):
        x = 10 + arg
        y = 200
        x = x * 10
        if x < y:
            x += 10
        return x + y
if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()
